/*
* sulky-modules - several general-purpose modules.
* Copyright (C) 2007-2016 Joern Huxhorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2007-2016 Joern Huxhorn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.huxhorn.sulky.junit;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
@SuppressWarnings({"PMD.SystemPrintln"})
@RunWith(Parameterized.class)
public class LoggingTestBase
{
protected boolean verbose = false;
protected boolean deleteLogFiles = false;
private Boolean logging;
private File loggingFile;
public LoggingTestBase(Boolean logging)
{
this.logging = logging;
}
@Parameters
public static Collection<Object[]> configs()
{
return Arrays.asList(new Object[][]{
{null},
{Boolean.TRUE},
{Boolean.FALSE},
});
}
@Before
public void setUpLogging()
throws IOException
{
loggingFile = null;
if (this.logging != null)
{
if (this.logging)
{
loggingFile = File.createTempFile("logging", "log");
enableAllLogging(loggingFile, verbose);
}
else
{
disableAllLogging(verbose);
}
}
else
{
resetLogging(verbose);
}
}
@After
public void tearDownLogging()
{
if (logging != null)
{
resetLogging(verbose);
}
if (loggingFile != null && deleteLogFiles)
{
if (!loggingFile.delete())
{
System.out.println("Couldn't delete file " + loggingFile.getAbsolutePath() + "!");
}
}
}
@SuppressWarnings({"PMD.AvoidPrintStackTrace"})
public static void resetLogging(boolean verbose)
{
if (verbose)
{
System.out.println("### Resetting logging configuration.");
}
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
if (loggerFactory instanceof LoggerContext)
{
LoggerContext loggerContext = (LoggerContext) loggerFactory;
// reset previous configuration initially loaded from logback.xml
if (verbose)
{
System.out.println("\nAbout to reset logging system.");
}
loggerContext.reset();
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(loggerContext);
URL configUrl;
configUrl = LoggingTestBase.class.getResource("/logback-test.xml");
if (configUrl == null)
{
configUrl = LoggingTestBase.class.getResource("/logback.xml");
}
try
{
configurator.doConfigure(configUrl);
if (verbose)
{
System.out.println("\nPrinting status of logging system:");
StatusPrinter.print(loggerContext);
}
}
catch (JoranException ex)
{
System.err.println("!!! Error configuring logging framework with '" + configUrl + "'!");
// this is not a bug! - Avoid Print Stack Trace : Avoid printStackTrace(); use a logger call instead.
ex.printStackTrace();
StatusPrinter.print(loggerContext);
}
}
}
@SuppressWarnings({"PMD.AvoidPrintStackTrace"})
private static void configureLoggingFromString(String loggingConfig, boolean verbose)
{
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
if (loggerFactory instanceof LoggerContext)
{
LoggerContext loggerContext = (LoggerContext) loggerFactory;
// reset previous configuration initially loaded from logback.xml
if (verbose)
{
System.out.println("\nAbout to reset logging system.");
}
loggerContext.reset();
byte[] stringBytes = loggingConfig.getBytes(StandardCharsets.UTF_8);
InputStream is = new ByteArrayInputStream(stringBytes);
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(loggerContext);
try
{
configurator.doConfigure(is);
if (verbose)
{
System.out.println("\nPrinting status of logging system:");
StatusPrinter.print(loggerContext);
}
}
catch (JoranException ex)
{
System.err.println("!!! Error configuring logging framework with '" + loggingConfig + "'!");
// this is not a bug! - Avoid Print Stack Trace : Avoid printStackTrace(); use a logger call instead.
ex.printStackTrace();
StatusPrinter.print(loggerContext);
}
}
}
/**
* This method disables all log events
*
* @param verbose if info about logging configuration should be written to System.out
*/
public static void disableAllLogging(boolean verbose)
{
if (verbose)
{
System.out.println("### Disabling all logging.");
}
/*
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.reset();
Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
root.setLevel(Level.OFF);
*/
String configString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<configuration>\n" +
" <root>\n" +
" <level value=\"OFF\"/>\n" +
" </root>\n" +
"</configuration>";
configureLoggingFromString(configString, verbose);
}
/**
* This method enables all log events and writes the logs to the given file. This is done to force
* evaluation of the log message and keep them off the console.
*
* @param file the file in which log messages will be written.
* @param verbose if info about logging configuration should be written to System.out
*/
public static void enableAllLogging(File file, boolean verbose)
{
if (verbose)
{
System.out.println("### Enabling all logging.\n### Logs are written to '" + file.getAbsolutePath() + "'.");
}
/*
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
if(verbose)
{
StatusPrinter.print(loggerContext);
}
loggerContext.reset();
Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
root.setLevel(Level.ALL);
PatternLayout patternLayout = new PatternLayout();
patternLayout.setPattern("%-4relative [%thread] %-5level %logger{35} - %msg%n");
patternLayout.setContext(loggerContext);
FileAppender<LoggingEvent> appender = new FileAppender<LoggingEvent>();
appender.setLayout(patternLayout);
appender.setFile(file.getAbsolutePath());
appender.setName("FILE");
appender.setContext(loggerContext);
root.addAppender(appender);
appender.start();
if(verbose)
{
System.out.println("### Status after enabling all logging.\n### Logs are written to '" + file.getAbsolutePath() + "'.");
StatusPrinter.print(loggerContext);
}
*/
String configString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<configuration>\n" +
" <appender name=\"FILE\" class=\"ch.qos.logback.core.FileAppender\">\n" +
" <File>" + file.getAbsolutePath() + "</File>\n" +
" <Append>true</Append>\n" +
" <layout class=\"ch.qos.logback.classic.PatternLayout\">\n" +
" <Pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</Pattern>\n" +
" </layout>\n" +
" </appender>\n" +
" <root>\n" +
" <level value=\"ALL\"/>\n" +
" <appender-ref ref=\"FILE\"/>\n" +
" </root>\n" +
"</configuration>";
configureLoggingFromString(configString, verbose);
}
}